#pragma once
#include"httplib.h"
#include"Util.hpp"
#include"Data.hpp"
#include<Windows.h>
#include <functional>
const static int server_port = 9999;
const static std::string server_ip = "121.37.22.58";
namespace cloud
{

	class Backup //文件备份类
	{

	private:
		std::string back_dir;//备份监控目录
		DataManger* data;
		std::mutex mtx;
		std::unordered_set<std::string> uploading_files; // 记录正在上传的文件
	public:

		std::string GbkToUtf8(const char* src_str)
		{
			int len = MultiByteToWideChar(CP_ACP, 0, src_str, -1, NULL, 0);
			wchar_t* wstr = new wchar_t[len + 1];
			memset(wstr, 0, len + 1);
			MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, len);
			len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
			char* str = new char[len + 1];
			memset(str, 0, len + 1);
			WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
			std::string strTemp = str;
			if (wstr) delete[] wstr;
			if (str) delete[] str;
			return strTemp;
		}
		Backup(const std::string& _back_dir, const std::string& backup_file)
		{
			back_dir = _back_dir;
			data = new DataManger(backup_file);
		}
		std::string GetfileIdentifier(const std::string& filename)
		{
			std::stringstream ss;
			FileUtil fu(filename);
			ss << fu.FileName() << "-" << fu.FileSize() << "-" << fu.LastMTime();
			return ss.str();
		}
		bool isUpload(const std::string& filename)
		{
			//如果文件没有上传或者文件被修改，则需要上传
			std::string id;
			if (data->GetOneByKet(filename, &id))//判断有无历史信息
			{
				if (id == GetfileIdentifier(filename))//true代表文件没有被修改过
				{
					return false;
				}
			}
			//文件上传，需要判断当前文件时候在一段时间没有修改，如果超过指定时间没有修改，则上传文件
			cloud::FileUtil fu(filename);
			if (time(nullptr) - fu.LastMTime() < 3)
			{
				return false;
			}
			if (uploading_files.find(filename) == uploading_files.end())
			{
					std::cout << filename << " need upload!\n";
					return true; // 如果文件正在上传，直接返回
			}
			return true;

		}

		bool UploadInternal(const std::string& filename)
		{
			cloud::FileUtil fu(filename);
			std::string body;
			fu.GetContent(&body);

			httplib::Client client(server_ip, server_port);
			struct httplib::MultipartFormData item;

			item.content = body;
			item.name = "file";
			item.filename = GbkToUtf8(fu.FileName().c_str());
			item.content_type = "application/octet-stream";

			httplib::MultipartFormDataItems items;
			items.push_back(item);

			client.set_write_timeout(120, 0);//设置写入超时
			client.set_read_timeout(120, 0);// 设置读取超时

			auto ret = client.Post("/upload", items);
			httplib::Error err = ret.error();
			std::cerr << "Exception occurred: " << err << std::endl;

			if (!ret || ret->status != 200)
			{
				std::cout << "upload fail" << std::endl;
				return false;
			}
			return true;
		}

		void Upload(const std::string& filename)
		{
			{
				std::lock_guard<std::mutex> lock(mtx); // 加锁，确保线程安全
				if (uploading_files.find(filename) != uploading_files.end())
				{
					return; // 如果文件正在上传，直接返回
				}
				uploading_files.insert(filename); // 标记文件为正在上传
			}

			std::thread([this, filename]() {
				if (UploadInternal(filename))
				{
					std::lock_guard<std::mutex> lock(mtx); // 加锁，确保线程安全
					data->Insert(filename, GetfileIdentifier(filename));
					uploading_files.erase(filename); // 上传完成后移除标记
					std::cout << "upload success: " << filename << std::endl;
				}
				else
				{
					std::lock_guard<std::mutex> lock(mtx); // 加锁，确保线程安全
					uploading_files.erase(filename); // 上传失败后移除标记
				}
				}).detach(); // 分离线程，使其独立运行
		}
		void RunModule()
		{
			while (true)
			{
				FileUtil fu(back_dir);
				std::vector<std::string> array;
				fu.ScanDirectory(&array);
				for (auto& e : array)
				{
					if (!isUpload(e))
						continue;
					try {
						Upload(e);
					}
					catch (const std::exception& e) {
						// 处理在RunModule中可能发生的异常
						std::cerr << "RunModule exception: " << e.what() << std::endl;
					}
				}
				Sleep(1);
			}
		}
	};
}

